#include "StdAfx.h"
#include "BurninRubberMachine.h"

CBurninRubberMachine::CBurninRubberMachine()
{
}

CBurninRubberMachine::~CBurninRubberMachine()
{
}

int CBurninRubberMachine::Init()
{
CBurgerTimeMachine::Init();
MainCPU->SetUser(this);
SoundCPU->SetUser(this);
MainCPU->SetRead(ReadMainCPU);
MainCPU->SetWrite(WriteMainCPU);
return(0);
}

void CBurninRubberMachine::Reset()
{
int n;

CBurgerTimeMachine::Reset();
for(n=0;n<0x10000;n++)
	NewROM[n] = Decrypt(MainROM[n]);
}

void CBurninRubberMachine::Frame()
{
do
	{
//	Line(49*2,33,1);							//overclock main cpu 2x, else game lags
	Line(49*2,33*2,1);						//overclock main cpu 2x, sound cpu 2x
	} while(Scanline != 0);
}

void CBurninRubberMachine::SaveState(CState *s)
{
CBurgerTimeMachine::SaveState(s);
s->Write8(Scroll2);
s->Write(BGRAM,0x200);
}

void CBurninRubberMachine::LoadState(CState *s)
{
CBurgerTimeMachine::LoadState(s);
Scroll2 = s->Read8();
s->Read(BGRAM,0x200);
}

void CBurninRubberMachine::RenderScreen(u8 *dest,int pitch)
{
if(Scroll)
	{
	memset(dest,0,256*pitch);
	RenderBackground(dest,pitch);
	RenderChars(dest,pitch,0x80);
	RenderSprites(dest,pitch);
	RenderChars(dest,pitch,0x7F);
	}
else
	{
	memset(dest,0,256*pitch);
	RenderChars(dest,pitch);
	RenderSprites(dest,pitch);
	}
}

static u8 tmpscr[256*(256*3)];

void CBurninRubberMachine::RenderBackground(u8 *dest,int pitch)
{
//todo: implement good horizontal scrolling
int offs,x,y,scroll;
u8 *b[3];

b[0] = BGROM + 0x0000;
b[1] = BGROM + 0x0000;
b[2] = BGROM + 0x1000;
scroll = ((Scroll & 2) * 128) + 511 - Scroll2;
if((VideoControl & 1) == 0)
	scroll = 512 - scroll;
for(offs=0;offs<0x200;offs++)
	{
	x = 16 * ((offs < 0x100) ? ((offs % 0x80) / 8) : ((offs % 0x80) / 8) + 16);
	y = 16 * (((offs % 0x100) < 0x80) ? offs % 8 : (offs % 8) + 8);
	x = 496 - x;
	if(VideoControl & 1)
		{
		x = 496 - x;
		y = 240 - y;
		}
	drawtile_16x16_or_notrans_bnj(tmpscr,256*2,(BGRAM[offs] >> 4) + ((offs & 0x80) >> 3) + 32,x,y,b,8);
	}
u8 *s = tmpscr + (512 - scroll) + 256;
u8 *d = dest;
for(y=0;y<256;y++)
	{
	memcpy(d,s,256);
	s += 256*2;
	d += pitch;
	}
}

u8 CBurninRubberMachine::ReadMainCPU(void *user,u32 addr)
{
CBurninRubberMachine *M = (CBurninRubberMachine*)user;

if(addr >= 0xA000)
	return(M->MainROM[addr]);
switch(addr & 0xFC00)
	{
	case 0x0000:
	case 0x0400:
		return(M->MainRAM[addr]);
	case 0x1000:
		switch(addr)
			{
			case 0x1000:	return((M->Dip[0] & 0x7F) | M->VBlank);
			case 0x1001:	return(M->Dip[1]);
			case 0x1002:	return(M->InputData[0]);
			case 0x1003:	return(M->InputData[1]);
			case 0x1004:	return(M->InputData[2]);
			}
		break;
	case 0x4000:
		return(M->VideoRAM[addr & 0x3FF]);
	case 0x4400:
		return(M->ColorRAM[addr & 0x3FF]);
	case 0x4800:
		addr &= 0x3FF;
		return(M->VideoRAM[MirrorRAMAddr(addr)]);
	case 0x4C00:
		addr &= 0x3FF;
		return(M->ColorRAM[MirrorRAMAddr(addr)]);
	case 0x5C00:
		if(addr < 0x5C10)
			return(M->PaletteRAM[addr & 0xF]);
		break;
	}
message("unhandled read (main cpu, addr $%04X)\n",addr);
return(0);
}

void CBurninRubberMachine::WriteMainCPU(void *user,u32 addr,u8 data)
{
CBurninRubberMachine *M = (CBurninRubberMachine*)user;

switch(addr & 0xFC00)
	{
	case 0x0000:
	case 0x0400:
		M->MainRAM[addr] = data;
		return;
	case 0x1000:
		switch(addr)
			{
			case 0x1000:		//?
				break;
			case 0x1001:
				M->VideoControl = data;
				return;
			case 0x1002:
				M->WriteSoundControl(data);
				return;
			}
		break;
	case 0x4000:
		M->VideoRAM[addr & 0x3FF] = data;
		return;
	case 0x4400:
		M->ColorRAM[addr & 0x3FF] = data;
		return;
	case 0x4800:
		addr &= 0x3FF;
		M->VideoRAM[MirrorRAMAddr(addr)] = data;
		return;
	case 0x4C00:
		addr &= 0x3FF;
		M->ColorRAM[MirrorRAMAddr(addr)] = data;
		return;
	case 0x5000:
		if(addr < 0x5200)
			{
			M->BGRAM[addr & 0x1FF] = data;
			return;
			}
		break;
	case 0x5400:
		if(addr == 0x5400)
			{
			M->Scroll = data;
			return;
			}
		break;
	case 0x5800:
		if(addr == 0x5800)
			{
			M->Scroll2 = data;
			return;
			}
		break;
	case 0x5C00:
		if(addr < 0x5C10)
			{
			M->WritePalette(addr & 0xF,data);
			return;
			}
		break;
	}
message("unhandled write (main cpu, addr $%04X = $%02X)\n",addr,data);
}
